/**
 * 函数工具类
 */
export class FunctionUtils {
  /**
   * 防抖函数，防止频繁触发事件
   * @param func 要执行的函数
   * @param delay 延迟时间，单位毫秒
   * @returns 防抖后的函数
   */
  static debounce = (func: (...args: any[]) => void, delay: number) => {
    let timerId: ReturnType<typeof setTimeout>
    return (...args: any[]): void => {
      clearTimeout(timerId)
      timerId = setTimeout(() => func.apply(this, args), delay)
    }
  }

  /**
   * 节流函数，限制函数执行频率
   * @param func 要执行的函数
   * @param interval 执行间隔（毫秒）
   * @param options 配置选项
   * @param options.leading 是否立即执行
   * @param options.trailing 是否在 trailing edge 执行
   * @returns 节流后的函数
   */
  static throttle = <T extends (...args: any[]) => void>(
    func: T,
    interval: number,
    options: { leading?: boolean, trailing?: boolean } = {
      leading: true,
      trailing: true,
    },
  ): ((this: ThisParameterType<T>, ...args: Parameters<T>) => void) => {
    let lastExecTime = 0
    let timerId: ReturnType<typeof setTimeout> | null = null
    let lastArgs: Parameters<T> | null = null

    return function (this: ThisParameterType<T>, ...args: Parameters<T>): void {
      const now = Date.now()

      // 立即执行（leading edge）
      if (options.leading && lastExecTime === 0) {
        func.apply(this, args)
        lastExecTime = now
        return
      }

      // 清除等待中的 trailing 执行
      if (timerId) {
        clearTimeout(timerId)
        timerId = null
      }

      // 计算剩余时间
      const remaining = interval - (now - lastExecTime)

      // 需要延迟执行
      if (remaining > 0) {
        lastArgs = args
        timerId = setTimeout(() => {
          if (options.trailing && lastArgs) {
            func.apply(this, lastArgs)
          }
          lastExecTime = Date.now()
          timerId = null
          lastArgs = null
        }, remaining)
      }
      else {
        // 可以立即执行
        func.apply(this, args)
        lastExecTime = now
      }
    }
  }

  /**
   * 增强版防抖函数
   * @param func 要执行的函数
   * @param wait 等待时间(毫秒)
   * @param immediate 是否立即执行
   */
  static enhanceDebounce<T extends (...args: any[]) => any>(
    func: T,
    wait: number,
    immediate: boolean = false,
  ): T & { flush: () => void } {
    let timeout: number | null = null
    let result: any

    const debounced = (...args: Parameters<T>) => {
      if (timeout) {
        clearTimeout(timeout)
      }

      if (immediate) {
        const callNow = !timeout
        timeout = window.setTimeout(() => {
          timeout = null
        }, wait)
        if (callNow) {
          result = func(...args)
        }
      }
      else {
        timeout = window.setTimeout(() => {
          func(...args)
        }, wait)
      }

      return result
    }

    // 添加 flush 方法
    const debouncedWithFlush = debounced as T & { flush: () => void }
    debouncedWithFlush.flush = () => {
      if (timeout) {
        clearTimeout(timeout)
        timeout = null
        // 这里不需要调用 func，因为 flush 只是取消延迟执行
      }
    }

    return debouncedWithFlush
  }

  /**
   * 获取类的所有方法名（包括原型链）
   */
  static getClassMethodNames(
    instance: any,
    options: {
      includeStatic?: boolean
      includeInherited?: boolean
      excludeConstructor?: boolean
      filterPrivate?: boolean
      customFilter?: (methodName: string, instance: any) => boolean
    } = {},
  ): string[] {
    const {
      includeStatic = false,
      includeInherited = true,
      excludeConstructor = true,
      filterPrivate = true,
      customFilter,
    } = options

    const methodNames = new Set<string>()

    // 获取实例方法
    this.collectInstanceMethods(instance, methodNames, {
      includeInherited,
      excludeConstructor,
      filterPrivate,
      customFilter,
    })

    // 获取静态方法
    if (includeStatic) {
      this.collectStaticMethods(instance.constructor, methodNames, {
        excludeConstructor,
        filterPrivate,
        customFilter,
      })
    }

    return Array.from(methodNames)
  }

  /**
   * 收集实例方法
   */
  private static collectInstanceMethods(
    instance: any,
    methodNames: Set<string>,
    options: {
      includeInherited: boolean
      excludeConstructor: boolean
      filterPrivate: boolean
      customFilter?: (methodName: string, instance: any) => boolean
    },
  ): void {
    let prototype = Object.getPrototypeOf(instance)

    while (prototype && prototype !== Object.prototype) {
      Object.getOwnPropertyNames(prototype)
        .filter(methodName => this.isValidMethod(methodName, prototype, options))
        .forEach(methodName => methodNames.add(methodName))

      if (!options.includeInherited) {
        break
      }
      prototype = Object.getPrototypeOf(prototype)
    }
  }

  /**
   * 收集静态方法
   */
  private static collectStaticMethods(
    constructor: any,
    methodNames: Set<string>,
    options: {
      excludeConstructor: boolean
      filterPrivate: boolean
      customFilter?: (methodName: string, instance: any) => boolean
    },
  ): void {
    Object.getOwnPropertyNames(constructor)
      .filter(methodName => this.isValidMethod(methodName, constructor, options))
      .forEach(methodName => methodNames.add(methodName))
  }

  /**
   * 检查是否是有效的方法
   */
  private static isValidMethod(
    methodName: string,
    target: any,
    options: {
      excludeConstructor: boolean
      filterPrivate: boolean
      customFilter?: (methodName: string, instance: any) => boolean
    },
  ): boolean {
    try {
      // 排除构造函数
      if (options.excludeConstructor && methodName === 'constructor')
        return false

      // 检查是否是函数
      if (typeof target[methodName] !== 'function')
        return false

      // 过滤私有方法（以下划线开头）
      if (options.filterPrivate && methodName.startsWith('_'))
        return false

      // 自定义过滤器
      return !(options.customFilter && !options.customFilter(methodName, target))
    }
    catch {
      return false
    }
  }

  /**
   * 获取方法的详细信息
   */
  static getMethodInfo(instance: any, methodName: string): {
    isOwnMethod: boolean
    isStatic: boolean
    descriptor: PropertyDescriptor | null
    definedIn: string
  } {
    const isStatic = typeof instance.constructor[methodName] === 'function'
    const target = isStatic ? instance.constructor : instance
    const descriptor = Object.getOwnPropertyDescriptor(target, methodName) || null

    return {
      isOwnMethod: descriptor !== undefined,
      isStatic,
      descriptor,
      definedIn: target.constructor.name,
    }
  }

  /**
   * 检查方法是否属于类
   */
  static hasMethod(instance: any, methodName: string, options?: {
    includeStatic?: boolean
    includeInherited?: boolean
  }): boolean {
    const methods = this.getClassMethodNames(instance, options)
    return methods.includes(methodName)
  }

  /**
   * Promise 检测函数
   */
  static isPromise<T>(value: any): value is Promise<T> {
    return value && typeof value === 'object' && typeof value.then === 'function'
  }
}
